package edu.gatech.oad.mule;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Rectangle;

import edu.gatech.oad.mule.model.GameStateMachine.GameState;
import edu.gatech.oad.mule.view.interfaces.RenderableTile;

/**
 * This class represents a space on the Map that is not a building. A tile
 * includes the types of land (plains, river, mountains, etc), as well as
 * generic floors and unpassable walls.
 * 
 * @author Brendan McGarry, Dale Avery, D'Miria Collins, Natasha Parekh, Jaemin
 *         Park
 * @version %I%, %G%
 */
public class Tile extends Zone implements RenderableTile {

	// width and height of tiles in pixels
	public static final int WIDTH = 75;
	public static final int HEIGHT = 75;
	public static final int DEFAULT_COST = 300;
	//tile owner
	private Player owner = null;
	//outfitted mule on this tile
	private MULE mule = null;
	//type of tile
	private char type;
	//resource values
	private int food = 0;
	private int energy = 0;
	private int smithore = 0;
	private int crystite = 0;
	//tile types
	public static final char RIVER = 'R';
	public static final char TOWN = 'T';
	public static final char PLAINS = 'P';
	public static final char MTN1 = '1';
	public static final char MTN2 = '2';
	public static final char MTN3 = '3';
	//does this tile have enough energy to produce resources?
	private boolean isEnergized;

	/**
	 * This constructor configures a new Tile object
	 * 
	 * @param x
	 *            The x-coordinate of the tile
	 * @param y
	 *            The y-coordinate of the tile
	 */
	public Tile(int x, int y, char type) {
		super(x * WIDTH, y * HEIGHT, WIDTH, HEIGHT);
		this.type = type;
		calculateProduction();
		isEnergized = false;
	}// end constructor

	/**
	 * Initializes the production values of each resource for this tile
	 */
	private void calculateProduction() {
		// river tiles are good at food
		if (type == RIVER) {
			food = 4;
			energy = 2;
		}// end if
			// plains tiles are good at energy
		else if (type == PLAINS) {
			food = 2;
			energy = 3;
			smithore = 1;
		}// end else if
			// mountains are good for smithore
		else if (type != TOWN) {
			food = 1;
			energy = 1;
			smithore = (int) type - 47;
		}// end else
	}// end method calculateProduction
	
	/**
	 * @return The Player who owns this plot of land
	 */
	public Player getOwner() {
		return owner;
	}// end method getOwner

	/**
	 * @return Whether or not this tile has a MULE on it
	 */
	public boolean hasMULE(){
		if(mule != null){
			return true;
		}//end if
		return false;
	}//end method hasMULE
	
	/**
	 * This tile produces resources based on the type of mule on the tile and
	 * the type of tile. The resources are deposited into the owners wallet
	 */
	public void produce() {
		// make sure someone owns this tile and has a mule on it
		if (owner != null && mule != null) {
			// energy mule = gather energy
			if (mule.getType() == MULE.ENERGY) {
				owner.addEnergy(energy);
			}// end if
				// food mule = gather food
			else if (mule.getType() == MULE.FOOD) {
				owner.addFood(food);
			}// end else if
				// smithore mule = gather smithore
			else if (mule.getType() == MULE.SMITHORE) {
				owner.addSmithore(smithore);
			}// end else if
				// crystite mule = gather crystite
			else if (mule.getType() == MULE.CRYSTITE) {
				owner.addCrystite(crystite);
			}// end else if
		}// end if
	}// end method getProduction
	
	/**
	 * Sets the amount of crystite at this location
	 * 
	 * @param amount The amount of crystite at this tile
	 */
	public void setCrystite(int amount){
		if(type != TOWN && type != RIVER){
			crystite = amount;
		}//end if
	}//end method setCrystite
	
	/**
	 * Sets the energized value for this tile.  If a tile is
	 * properly energized, then it can produce resources for the
	 * player.  Otherwise, it has a possibility of not producing
	 * 
	 * @param isEnergized Whether or not this tile is energized
	 */
	public void setEnergized(boolean isEnergized){
		this.isEnergized = isEnergized;
	}//end method setEnergized
	
	/**
	 * Sets the owner of this tile. If someone already owns this tile, you
	 * cannot change the owner. A tile must be disowned first.
	 * 
	 * @param owner
	 *            The new owner of this tile. Pass in null to disown
	 */
	private void setOwner(Player owner) {
		if (this.owner == null || owner == null) {
			// do it
			this.owner = owner;
		}// end if
	}// end method setOwner

	/*
	@Override
	public void interact(Player p) {
		// just call the regular interact method with the INTRO state.
		interact(p, GameState.INTRO);
	}//end method interact
	*/
	
	@Override
	public void interact(Player p, GameState phase, int round, int time) {

		// when a player attempts to interact with a tile, these
		// are the possible actions that can happen:
		// 1) The tile isn't owned by anyone yet and now becomes
		// owned by the player
		// 2) The tile is owned by the player, and the player
		// places an outfitted mule on the tile
		// 3) the tile is owned by the player and has a mule
		// harvesting from it. Take the mule off the tile
		
		//you cannot do anything to the town tile
		if(type != TOWN){
			
			//land grant phase logic.  This logic deals with the
			//  purchasing of new plots of land
			if(phase == GameState.LAND_GRANT){
				System.out.print(p.getName() + " goes to claim a tile with [" + p.getMoney() + "]. ");
				//the game is in the land grant phase and it is the
				//  first or second round...
				if(round < 2){
					//...then land is free
					owner = p;
					p.addTile();
					System.out.print(p.getName() +  " recieved " + 
							this.toString() + " for [0]. ");
				}//end if
				//the game is in land grand phase, but we aren't handing
				//  out land for free anymore
				else{
					//player has enough money to buy this plot of land
					if(p.getMoney() >= DEFAULT_COST){
						//set the owner
						owner = p;
						p.addTile();
						//subtract the funds
						p.addMoney(-1 * DEFAULT_COST);
						System.out.print(p.getName() + " bought " + 
								this.toString() + " for [" + DEFAULT_COST + "]. ");
					}//end if
					//player doesn't have enough money
					else{
						System.out.print(p.getName() + " has insufficient funds. ");
					}//end else
				}//end else if
				System.out.println(p.getName() + " leaves with [" + p.getMoney() + "].");
			}//end if
			
			//we are in the development phase.  this logic is used for placing and
			//  taking MULEs off plots of land
			else if(phase == GameState.DEVELOPMENT){
				//this tile is owned by the player
				if(owner != null && owner.equals(p)){
					//the player has a MULE to place on the tile and the tile
					//  doesn't already have a MULE on it
					if(p.hasOutfittedMULE() && mule == null){
						mule = p.getMULE();
						p.setMULE(null);
						System.out.println(p.getName() + " deployed MULE on " + this.toString());
					}//end if
					//this tile has one of the player's MULEs and the player wants
					//  to take it back
					else if(mule != null && p.getMULE() == null){
						p.setMULE(mule);
						mule = null;
						System.out.println(p.getName() + " removed MULE from " + this.toString());
					}//end else if
				}//end if
				//the tile is not owned by this player.  When the player
				//  attempts to place the MULE on this tile, it will run free
				else if((owner == null && p.hasOutfittedMULE()) || (owner != null && !owner.equals(p) && p.hasOutfittedMULE())){
					p.setMULE(null);
					System.out.println(p.getName() + " attempted to deploy MULE on " + this.toString() +
							".  The MULE gallops off into the sunset as it breaks free.");
				}//end else if
				else{
					System.out.println("cannot interact; " + p.getName() + " does not own this tile.");
				}//end else
			}//end else if
			
		}//end if
		else{
			System.out.println("Cannot interact with " + this.toString());
		}//end else
	}// end method interact
	
	@Override
	public String toString() {
		//return (type + "[" + crystite + "]: (" + getX() + "," + getY() + ")");
		return (type + "[" + crystite + "]");
	}// end method toString

	// ==============================
	// RenderableTile
	// ==============================

	@Override
	public TileType getTileType() {
		if (type == TOWN) {
			return TileType.TOWN;
		}// end if
		else if (type == RIVER) {
			return TileType.RIVER;
		}// end else if
		else if (type == PLAINS) {
			return TileType.PLAINS;
		}// end else if
		else if (type == MTN1) {
			return TileType.MOUNTAINS_1;
		}// end else if
		else if (type == MTN2) {
			return TileType.MOUNTAINS_2;
		}// end else if
		else if (type == MTN3) {
			return TileType.MOUNTAINS_3;
		}// end else if
		return TileType.ERROR;
	}// end method getTileType

	@Override
	public ProductionType getProductionType() {
		if (mule == null) {
			return ProductionType.NO_MULE;
		}// end if
		else if (mule.getType() == MULE.ENERGY) {
			return ProductionType.ENERGY;
		}// end else if
		else if (mule.getType() == MULE.FOOD) {
			return ProductionType.FOOD;
		}// end else if
		else if (mule.getType() == MULE.SMITHORE) {
			return ProductionType.SMITHORE;
		}// end else if
		else if (mule.getType() == MULE.CRYSTITE) {
			return ProductionType.CRYSTITE;
		}// end else if
		return ProductionType.ERROR;
	}// end emthod getProductionType

	@Override
	public boolean isEnergized() {
		return isEnergized;
	}// end method

	@Override
	public Color getOwnerColor() {
		if (owner != null) {
			return owner.getColor();
		}// end if
		return null;
	}// end method getOwnerColor
	
}// end class Tile

